package serie06.util;

import java.util.EnumMap;
import java.util.Map;

public class StdStock<E extends Enum<E>> implements Stock<E>, Cloneable {
	
	// ATTRIBUTS
	
	private Map<E, Integer> stock;
	
	// CONSTRUCTEURS
	
	/** 
	 * Modelise un stock d' elements.
	 * @post
	 *     forall e:E : getNumber(e) == 0
	 */
	public StdStock(Class<E> keyE) {
		stock = new EnumMap<E, Integer>(keyE);
		for (E e : keyE.getEnumConstants()) {
			stock.put(e, 0);
		}
	}
	
	// REQUETES
	
    public int getNumber(E e) {
    	if (e == null) {
    		throw new IllegalArgumentException("Mauvais élément");
    	}
    	return stock.get(e);
    }
    
    public int getTotalNumber() {
    	int accu = 0;
    	for (E e : stock.keySet()) {
    		accu += stock.get(e);
    	}
    	return accu;
    }
    
	@SuppressWarnings("unchecked")
	public Stock<E> clone() {
    	StdStock<E> clone = null;
    	try {
    		clone = (StdStock<E>) super.clone();
    	} catch (CloneNotSupportedException e) {
    		throw new InternalError("échec clonage");
    	}
    	clone.stock = ((EnumMap<E, Integer>) stock).clone();
    	return clone;
    }
	
	/**
	 * On redefinit la methode equals.
	 */
	@SuppressWarnings("unchecked")
	public boolean equals(Object obj) {
		if (obj != null && obj.getClass() == this.getClass()) {
			StdStock<E> o = (StdStock<E>) obj;
			for (E e : stock.keySet()) {
				if (this.stock.get(e) != o.stock.get(e)) {
					return false;
				}
			}
			return true;
		}
		return false;
	}
	
	/**
	 * On redefinit la methode hashCode.
	 */
	public int hashCode() {
		return stock.hashCode();
	}

    // COMMANDES
   
    public void addElement(E e) {
    	addElement(e, 1);
    }
    
    public void addElement(E e, int qty) {
    	if (e == null) {
    		throw new IllegalArgumentException("Mauvais élément");
    	}
    	if (qty <= 0) {
    		throw new IllegalArgumentException("Quantite negative");
    	}
    	int tmp = stock.get(e) + qty;
    	stock.put(e, tmp);
    }
    
    public void fill(int max) {
    	if (max <= 0) {
    		throw new IllegalArgumentException("Impossible de remplir");
    	}
    	for (E e : stock.keySet()) {
    		stock.put(e, max);
    	}
    }
    
    public void removeElement(E e) {
    	removeElement(e, 1);
    }
    
    public void removeElement(E e, int qty) {
    	if (e == null) {
    		throw new IllegalArgumentException("Mauvais élément");
    	}
    	if (qty <= 0) {
    		throw new IllegalArgumentException("Quantite negative");
    	}
    	if (getNumber(e) < qty) {
    		throw new IllegalArgumentException("Impossibilite");
    	}
    	int tmp = stock.get(e) - qty;
    	stock.put(e, tmp);
    }
    
    public void reset() {
    	for (E e : stock.keySet()) {
    		stock.put(e, 0);
    	}
    }

}
